#import "EventManager.h"

// The shared instance of EventManager
static EventManager* sharedEventManager = nil;

/**
 * An EventManager is an object representing the management
 * system for all event-oriented tasks.
 *
 * The event manager is the main interface into the event subsystem, and all
 * calls from outside modules should only need to communicate with this class.
 *
 * The event manager deallocates all dependent shared instances, and thus it 
 * is on the onus of the caller of this class to call the deallocate method
 * after there is no longer any need to interface with the event subsystem.
 *
 * Maintenance of both cached and persistent events is handled by the event
 * manager. The class also serves as the delegate of the event viewer 
 * (e.g. handling bookmark/unbookmark requests).
 *
 * The event manager can be used to do the following tasks:
 *      1) Search for events from SFU websites using keyword filters.
 *      2) Search for events from SFU websites using keyword filters and then
 *         filter only the events with a parsable location on campus.
 *      3) Display the information about a single event or a list of events.
 *      4) Display the bookmarked (persistent) events.
 *      5) Send a request to view the location of an event on a map.
 * 
 * @author      James Lin
 * @version     0.9.1
 * @since       0.7.0
 */
@implementation EventManager

/**
 * Retrieve the shared instance of the event manager.
 *
 * @return  the shared instance of EventManager
 */
+ (EventManager*)sharedEventManager {
	@synchronized(self) {
		if (sharedEventManager == nil) {
			sharedEventManager = [[EventManager alloc] init];
		}
		return sharedEventManager;
	}
}

/**
 * Allocate the event manager.
 *
 * @return  the newly allocated shared instance of EventManager
 */
+ (id) alloc {
	@synchronized(self) {
		sharedEventManager = [super alloc];
		return sharedEventManager;
	}
}

/**
 * Retrieve a copy of the event manager.
 *
 * @return  the shared instance of EventManager
 */
+ (id) copy {
	@synchronized(self) {
		return sharedEventManager;
	}
}

/**
 * Initialize the shared instance of the shared event manager.
 *
 * Creates an empty event cache and loads the bookmarked events from disk.
 *
 * @return  the initialized shared event manager
 */
- (id)init {
	if (self = [super init]) {
		cachedEvents = [[SFUEventCollection alloc] init];
		storedEvents = [[SFUPersistentEventCollection alloc] 
						initWithFile:BOOKMARKED_EVENTS_FILENAME];
	}
	return self;
}

/**
 * Get the delegate handling search events.
 *
 * @return  the delegate handling search events
 * @see     SFUEventSearchEngineDelegate
 */
- (id<SFUEventSearchEngineDelegate>)searchDelegate {
	return searchEngineDelegate;
}

/**
 * Set the delegate handling search events.
 *
 * @param delegate  the delegate handling search events
 * @see             SFUEventSearchEngineDelegate
 */
- (void)setSearchDelegate:(id<SFUEventSearchEngineDelegate>)delegate {
	searchEngineDelegate = delegate;
}

/**
 * Set the delegate handling view building events.
 *
 * @param delegate  the delegate handling view building events
 * @see             MapBuildingSearchDelegate
 */
- (void)setViewBuildingDelegate:(id<MapBuildingSearchDelegate>)delegate {
	viewBuildingDelegate = delegate;
}


/**
 * Retrieve bookmarked events.
 *
 * @return  an array of all the bookmarked events
 */
- (NSArray*)getBookmarkedEvents {
	return [storedEvents getEvents];
}

/**
 * Search for events by a list of keywords.
 *
 * The search engine delegate must be set prior to the search
 * to handle any search events.
 *
 * @param keywords  a list of keywords
 * @param matchAll  YES if all keywords in the keyword list must match;
 *                  NO if any keyword can match.
 */
- (void)searchEventsByKeywords:(NSArray*)keywords 
			  matchAllKeywords:(BOOL)matchAll {
	[[SFUEventSearchEngine sharedSearchEngine] setDelegate:searchEngineDelegate];
	[[SFUEventSearchEngine sharedSearchEngine] findEventsWithKeywords:keywords
													 matchAllKeywords:matchAll];
}

/**
 * Search for events by a spaced-delimited string of keywords.
 *
 * The search engine delegate must be set prior to the search
 * to handle any search events.
 *
 * @param keyword   a space-delimited string of keywords
 * @param matchAll  YES if all keywords in the keyword list must match;
 *                  NO if any keyword can match.
 */
- (void)searchEventsByKeywordString:(NSString*)keyword 
				   matchAllKeywords:(BOOL)matchAll {
	[self searchEventsByKeywords:[keyword componentsSeparatedByString:@" "]
				matchAllKeywords:matchAll];
}

/**
 * Search for events by a spaced-delimited string of keywords.
 *
 * The search engine delegate must be set prior to the search
 * to handle any search events.
 *
 * @param keyword      a space-delimited string of keywords
 * @param matchAll     YES if all keywords in the keyword list must match;
 *                     NO if any keyword can match.
 * @param hasLocation  whether the events must have a location
 */
- (void)searchLocEventsByKeywordString:(NSString*)keyword 
					  matchAllKeywords:(BOOL)matchAll 
						   hasLocation:(BOOL)hasLocation {
	[SFUEventSearchEngine sharedSearchEngine].locationEventsOnly = hasLocation;
	[self searchEventsByKeywordString:keyword
					 matchAllKeywords:matchAll];
}

/**
 * Display information about an event.
 *
 * Creates a new view for displaying the event information and pushes
 * that view onto the navigation controller stack of the parent
 * view. Upon tapping the back button, the view is automatically 
 * popped off the top of the navigation stack.
 *
 * @param event          the event to display
 * @param navController  the navigation controller of the parent view
 */
- (void)displayEvent:(SFUEvent*)event 
	   navController:(UINavigationController*)navController {
	if ([storedEvents getEventWithKey:[event getKey]] != nil) {
		event.isBookmarked = YES;
	}
	[[EventViewer sharedEventViewer] setDelegate:self];
	[[EventViewer sharedEventViewer] displayEvent:event 
									navController:navController];
}

/**
 * Display information about a list of events.
 *
 * Creates a new view for displaying the list of events and pushes
 * that view onto the navigation controller stack of the parent
 * view. Upon tapping the back button, the view is automatically 
 * popped off the top of the navigation stack.
 *
 * @param events         the list of events to display
 * @param navController  the navigation controller of the parent view
 */
- (void)displayEvents:(NSArray*)events 
		navController:(UINavigationController*)navController {
	for (SFUEvent* event in events) {
		if ([storedEvents getEventWithKey:[event getKey]] != nil) {
			event.isBookmarked = YES;
		}
	}
	[[EventListViewer sharedEventListViewer] setDelegate:self];
	[[EventListViewer sharedEventListViewer] displayEventList:events 
												navController:navController];
}

/**
 * Display an event search view
 *
 * @param navController  the navigation controller of the parent view
 * @param delegate       the delegate handling event search results
 */
+ (void)searchEventsWithNavController:(UINavigationController*)navController 
					   searchDelegate:(id<SFUEventSearchEngineDelegate>)delegate {
	[[EventSearchView sharedEventSearchView] displayWithNavController:navController 
													   searchDelegate:delegate];
}

/**
 * Display the list of bookmarked events.
 *
 * Creates a new view for displaying the list of events and pushes
 * that view onto the navigation controller stack of the parent
 * view. Upon tapping the back button, the view is automatically 
 * popped off the top of the navigation stack.
 *
 * @param navController  the navigation controller of the parent view
 * @return               whether there are bookmarks to display
 */
- (BOOL)displayBookmarkedWithNavController:(UINavigationController*)navController {
	if ([storedEvents size] > 0) {
		[[EventListViewer sharedEventListViewer] setDelegate:self];
		[[EventListViewer sharedEventListViewer] displayEventList:[storedEvents getEvents]
													navController:navController];
		return YES;
	} else {
		UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:@"You have no bookmarked events!" 
															 message:@"" 
															delegate:self 
												   cancelButtonTitle:@"Ok" 
												   otherButtonTitles:nil] autorelease];
		[alertView show];
		return NO;
	}
}

/**
 * Handle a request to bookmark a given event.
 *
 * Bookmarked events should be treated as persistent data.
 *
 * @param event  the event to bookmark
 * @return       whether request was granted and successful
 * @see          EventViewerDelegate
 */
- (BOOL)eventShouldBookmark:(SFUEvent*)event {
	[storedEvents addEvent:event];
	return [storedEvents containsEvent:event];
}

/**
 * Handle a request to delete a given bookmarked event.
 *
 * Bookmarked events should be treated as persistent data.
 *
 * @param event  the bookmarked event to delete
 * @return       whether request was granted and successful
 * @see          EventViewerDelegate
 */
- (BOOL)eventShouldDelete:(SFUEvent*)event {
	[storedEvents removeEvent:event];
	return ![storedEvents containsEvent:event];
}

/**
 * Handle a request to view the location of a given event.
 *
 * @param event  the event to bookmark
 * @return       whether request was granted and successful
 * @see          EventViewerDelegate
 */
- (void)viewLocationOfEvent:(SFUEvent*)event {
	if (viewBuildingDelegate != nil) {
		Building* b = [ParsingUtilities parseBuildingFromString:event.eventLocation];
		[viewBuildingDelegate searchRequestByBuilding:b isNew:NO];
	}
}

/**
 * Deallocate the event manager.
 */
- (void)dealloc {
	[cachedEvents release];
	[storedEvents release];
	[sharedEventManager release];
    [super dealloc];
}

@end
